#pragma once
#include <boost/unordered_map.hpp>
#include <string>
#include <Logger.h>
#include <boost/foreach.hpp>
#include <boost/shared_ptr.hpp>
#include <ITraverse.h>

namespace grflib { namespace engine	{ namespace core {

    ///////////////////////////////////////////////////
    //SINGLETON manager base class
    template<typename TMan, 
        typename TObj, 
        int TId = 0, 
        typename TKey = std::string,
        typename TPtr = boost::shared_ptr<TObj>>
    class _CManagerBaseSingle
    {
    public:
        virtual ~_CManagerBaseSingle(void);

        static TMan *Instance(void);
        static int GetId(void) {return managerId;}

        //object management
        bool AddObj(const TKey &name, TPtr &pObj);
        void RemoveObj(const TKey &name);
        TPtr & FindObj(const TKey &name); //returns 0 if not found
        TPtr & operator[] (const TKey &name);

        //traversing
        HRESULT Traverse(const IMemberCaller<TObj> &func);
        //HRESULT Traverse(const IMemberPtrCaller<TObj> &func);
        void Clear(void);

    protected:
        typedef typename boost::unordered_map<TKey, TPtr>::iterator obj_iter_type;
        typedef typename boost::unordered_map<TKey, TPtr>::reference obj_ref_type;
        typedef TKey key_type;
        _CManagerBaseSingle(void); //prevents manual instantiation
        boost::unordered_map<TKey, TPtr> m_store;

        static const int managerId = TId; //dummy variable

    };
    ///////////////////////////////////////////////////

    ///////////////////////////////////////////////////
    //instantiable manager base class
    template<typename TObj, 
        typename TKey = std::string,
        typename TPtr = boost::shared_ptr<TObj>>
    class _CManagerBase
    {
    public:
        _CManagerBase(void);
        virtual ~_CManagerBase(void);

        //object management
        bool AddObj(const TKey &name, TPtr &pObj);
        void RemoveObj(const TKey &name);
        TPtr & FindObj(const TKey &name);
        bool GetObjName(TKey &name, const TPtr &pObj);
        TPtr & operator[] (const TKey &name);

        //traversing
        HRESULT Traverse(const IMemberCaller<TObj> &func);
        //HRESULT Traverse(const IMemberPtrCaller<TObj> &func);
        HRESULT AbortableTraverse(const IMemberCaller<TObj> &func);
        void Clear(void);

    protected:
        typedef typename boost::unordered_map<TKey, TPtr>::iterator obj_iter_type;
        typedef typename boost::unordered_map<TKey, TPtr>::reference obj_ref_type;
        typedef TKey key_type;
        typedef TObj obj_type;
        boost::unordered_map<TKey, TPtr> m_store;

    };
    ///////////////////////////////////////////////////
}}} //namespaces

#include <ManagerBaseImpl.hpp>